#include <arpa/inet.h>   // 提供网络地址转换函数
#include <errno.h>       // 定义错误码
#include <fcntl.h>       // 文件操作相关函数
#include <netinet/in.h>  // 定义网络协议的结构体和函数
#include <pthread.h>     // 引入pthread库
#include <signal.h>      // 提供信号处理函数
#include <stdio.h>       // 标准输入输出
#include <stdlib.h>      // 标准库函数，如exit()
#include <string.h>      // 字符串操作函数
#include <sys/socket.h>  // 套接字相关函数
#include <sys/time.h>    // 提供 gettimeofday 函数
#include <sys/types.h>   // 定义数据类型
#include <time.h>        // 时间相关函数
#include <unistd.h>      // 提供POSIX API，如read()、write()

#include "Cache.h"
#include "thpool.h"

#define VERSION 23     // 服务器版本号
#define BUFSIZE 8096   // 缓冲区大小
#define ERROR 42       // 错误日志类型
#define LOG 44         // 普通日志类型
#define FORBIDDEN 403  // HTTP状态码：禁止访问
#define NOTFOUND 404   // HTTP状态码：未找到资源

// 支持的文件扩展名及其对应的MIME类型
struct {
    char *ext;       // 文件扩展名
    char *filetype;  // MIME类型
} extensions[] = {
    {"gif", "image/gif"},
    {"jpg", "image/jpg"},
    {"jpeg", "image/jpeg"},
    {"png", "image/png"},
    {"ico", "image/ico"},
    {"zip", "image/zip"},
    {"gz", "image/gz"},
    {"tar", "image/tar"},
    {"htm", "text/html"},
    {"html", "text/html"},
    {0, 0}  // 结束标志
};

// 计时变量，分别记录每个线程池的总时间和任务数量
long total_read_msg_time = 0;
long total_read_file_time = 0;
long total_send_msg_time = 0;
int read_msg_count = 0;
int read_file_count = 0;
int send_msg_count = 0;

Cache *cache;  // 缓存

typedef struct {
    int hit;
    int fd;
} webparam;

typedef struct {
    char filename[BUFSIZE];
    int socket_fd;
} filename_msg;

typedef struct {
    char *file_content;
    int socket_fd;
} msg;

pthread_mutex_t filename_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t msg_queue_mutex = PTHREAD_MUTEX_INITIALIZER;

// 线程池初始化
threadpool read_msg_pool;
threadpool read_file_pool;
threadpool send_msg_pool;

void *read_msg(void *data);
void *read_file(void *data);
void *send_msg(void *data);

// 信号处理函数，用于切换调度算法
void sigint_handler_for_shift(int signum) {
    
    SwitchToOther(cache);
}

// 信号处理函数，用于捕捉 SIGINT 并打印时间统计
void sigint_handler(int signum) {
    printf("\nCaught signal %d: Stats for I/O operations\n", signum);
    printf("Total Requests: %d | %d | %d\n", read_msg_count, read_file_count, send_msg_count);
    if (read_msg_count > 0)
        printf("Average read_msg time: %ld us\n", total_read_msg_time / read_msg_count);
    if (read_file_count > 0)
        printf("Average read_file time: %ld us\n", total_read_file_time / read_file_count);
    if (send_msg_count > 0)
        printf("Average send_msg time: %ld us\n", total_send_msg_time / send_msg_count);

    exit(0);  // 退出程序
}

// 计算两个时间点之间的时间差（以微秒为单位）
long calculate_time_diff(struct timespec start, struct timespec end) {
    long diff_sec = end.tv_sec - start.tv_sec;     // 秒部分差值
    long diff_nsec = end.tv_nsec - start.tv_nsec;  // 纳秒部分差值
    return diff_sec * 1000000 + diff_nsec / 1000;  // 转换为微秒
}

// 定义互斥锁用于保护日志文件
pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;

// 日志记录
void logger(int type, const char *s1, const char *s2, int socket_fd) {
    int fd;
    char logbuffer[BUFSIZE * 2];
    char timebuffer[64];

    struct timeval tv;
    gettimeofday(&tv, NULL);

    struct tm *tm_info = localtime(&tv.tv_sec);
    strftime(timebuffer, sizeof(timebuffer), "%Y-%m-%d %H:%M:%S", tm_info);

    char full_timebuffer[256];
    snprintf(full_timebuffer, sizeof(full_timebuffer), "[%s.%03ld]", timebuffer, tv.tv_usec / 1000);

    switch (type) {
        case ERROR:
            snprintf(logbuffer, sizeof(logbuffer), "%s [ERROR] %s:%s Errno=%d exiting pid=%d",
                     full_timebuffer, s1, s2, errno, getpid());
            break;
        case FORBIDDEN:
            if (write(socket_fd,
                      "HTTP/1.1 403 Forbidden\nContent-Length: 185\nConnection: "
                      "close\nContent-Type: text/html\n\n"
                      "<html><head>\n<title>403 "
                      "Forbidden</title>\n</head><body>\n<h1>Forbidden</h1>\n"
                      "The requested URL, file type or operation is not allowed on this simple "
                      "static file webserver.\n"
                      "</body></html>\n",
                      271) < 0) {
                perror("Failed to send 403 Forbidden response");
            }
            snprintf(logbuffer, sizeof(logbuffer), "%s [FORBIDDEN] %s:%s", full_timebuffer, s1, s2);
            break;
        case NOTFOUND:
            if (write(socket_fd,
                      "HTTP/1.1 404 Not Found\nContent-Length: 136\nConnection: "
                      "close\nContent-Type: text/html\n\n"
                      "<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not "
                      "Found</h1>\n"
                      "The requested URL was not found on this server.\n</body></html>\n",
                      224) < 0) {
                perror("Failed to send 404 Not Found response");
            }
            snprintf(logbuffer, sizeof(logbuffer), "%s [NOT FOUND] %s:%s", full_timebuffer, s1, s2);
            break;
        case LOG:
            snprintf(logbuffer, sizeof(logbuffer), "%s [INFO] %s:%s:%d", full_timebuffer, s1, s2,
                     socket_fd);
            break;
    }

    // 加锁保护日志文件写入
    pthread_mutex_lock(&log_mutex);
    if ((fd = open("webserver.log", O_CREAT | O_WRONLY | O_APPEND, 0644)) >= 0) {
        if (write(fd, logbuffer, strlen(logbuffer)) < 0) {
            perror("Failed to write log to file");
        }
        if (write(fd, "\n", 1) < 0) {
            perror("Failed to write newline to log file");
        }
        close(fd);
    } else {
        perror("Failed to open log file");
    }

    pthread_mutex_unlock(&log_mutex);
}

//------反序列化并推送给read_file_pool
// 读取客户端请求消息并加入filename队列
void *read_msg(void *data) {
    int fd;
    int hit;
    char buffer[BUFSIZE + 1];
    webparam *param = (webparam *)data;
    fd = param->fd;
    hit = param->hit;

    //-----记录时间
    struct timespec start, end;
    clock_gettime(CLOCK_MONOTONIC, &start);
    
    int ret = read(fd, buffer, BUFSIZE);     // 读取客户端请求
    if (ret <= 0) {
        logger(FORBIDDEN, "Failed to read browser request", "", fd);
        close(fd);    // 关闭套接字
        free(param);  // 释放内存
        return NULL;
    }


    //----反序列化
    // 清除换行符和回车符
    for (int i = 0; i < ret; i++) {
        if (buffer[i] == '\r' || buffer[i] == '\n') buffer[i] = '*';
    }

    // 检查是否为GET请求
    if (strncmp(buffer, "GET ", 4)) {
        logger(FORBIDDEN, "Only simple GET operation supported", buffer, fd);
        close(fd);    // 关闭套接字
        free(param);  // 释放内存
        return NULL;
    }

    // 截取文件路径
    int i;
    for (i = 4; i < BUFSIZE; i++) {
        if (buffer[i] == ' ') {
            buffer[i] = 0;
            break;
        }
    }

    // 检查路径是否合法
    for (int j = 0; j < i - 1; j++) {
        if (buffer[j] == '.' && buffer[j + 1] == '.') {
            logger(FORBIDDEN, "Parent directory (..) path names not supported", buffer, fd);
            close(fd);    // 关闭套接字
            free(param);  // 释放内存
            return NULL;
        }
    }

    // 默认返回 index.html
    if (!strncmp(&buffer[0], "GET /\0", 6)) {
        strcpy(buffer, "GET /index.html");
    }

    // 文件类型解析
    char *fstr = NULL;
    int buflen = strlen(buffer);
    for (i = 0; extensions[i].ext != 0; i++) {
        int len = strlen(extensions[i].ext);
        if (!strncmp(&buffer[buflen - len], extensions[i].ext, len)) {
            fstr = extensions[i].filetype;
            break;
        }
    }

    if (fstr == NULL) {
        logger(FORBIDDEN, "File extension type not supported", buffer, fd);
        close(fd);    // 关闭套接字
        free(param);  // 释放内存
        return NULL;
    }

    // 动态分配filename_msg结构体并填充数据
    filename_msg *filename_msg_param = malloc(sizeof(filename_msg));
    strcpy(filename_msg_param->filename, buffer + 5);  // 从GET之后开始的文件名
    filename_msg_param->socket_fd = fd;

    // 将任务加入read_file线程池
    thpool_add_work(read_file_pool, read_file, filename_msg_param);
    logger(LOG, "read_file added to thpool", filename_msg_param->filename, fd);

    free(param);  // 释放read_msg中使用的内存

    clock_gettime(CLOCK_MONOTONIC, &end);
    long duration = calculate_time_diff(start, end);
    total_read_msg_time += duration;  // 累加read_msg的时间
    read_msg_count++;                 // 统计read_msg操作次数

    return NULL;
}

//------从cache中读取数据并推送给send_msg_pool
// 从filename队列读取文件并加入msg队列
void *read_file(void *data) {
        printf("read_file start!!!!!!!!!\r\n\n");

    filename_msg *filename_msg_param = (filename_msg *)data;  // 接收从read_msg传递过来的filename_msg结构体指针

    // 动态分配msg结构体并填充数据
    msg *file_msg = malloc(sizeof(msg));

    file_msg->socket_fd = filename_msg_param->socket_fd;

    // 从cache中读取文件内容
    printf("get_from_cache start!!!!!!!!!\r\n");
    char *file_content = get_from_cache(cache,filename_msg_param->filename);
    printf("get_from_cache success!!!!!!!!!\r\n\n");

    if (file_content != NULL) {
        file_msg->file_content = file_content;
        logger(LOG, "File found in cache", filename_msg_param->filename, file_msg->socket_fd);
    } 
    else
    {
        logger(LOG, "read_file read NULL digital", filename_msg_param->filename, file_msg->socket_fd);
        return NULL;
    }
    // 将任务加入send_msg线程池
    thpool_add_work(send_msg_pool, send_msg, file_msg);
    logger(LOG, "send_msg added to thpool", file_msg->file_content, file_msg->socket_fd);
    printf("read_file end!!!!!!!!\r\n\n");
    return NULL;
}




// 从msg队列发送文件内容到客户端
void *send_msg(void *data) {
    msg *file_msg = (msg *)data;  // 接收从read_file传递过来的msg结构体指针

    struct timespec start, end;
    clock_gettime(CLOCK_MONOTONIC, &start);

    // 发送HTTP响应头
    char header[BUFSIZE];
    int len = strlen(file_msg->file_content);
    sprintf(header,
            "HTTP/1.1 200 OK\nServer: nweb/%d.0\nContent-Length: %d\nConnection: "
            "close\nContent-Type: text/html\n\n",
            VERSION, len);

    // 向客户端发送响应头
    if (write(file_msg->socket_fd, header, strlen(header)) < 0) {
        logger(ERROR, "Failed to write HTTP header", "", file_msg->socket_fd);
        close(file_msg->socket_fd);
        // free(file_msg->file_content);  // 释放内存
        free(file_msg);  // 释放内存
        return NULL;
    }

    // 向客户端发送文件内容
    if (write(file_msg->socket_fd, file_msg->file_content, len) < 0) {
        logger(ERROR, "Failed to write file content", "", file_msg->socket_fd);
    }

    clock_gettime(CLOCK_MONOTONIC, &end);
    long duration = calculate_time_diff(start, end);
    total_send_msg_time += duration;  // 记录文件写入时间
    send_msg_count++;                 // 统计send_msg操作次数

    // 关闭套接字
    close(file_msg->socket_fd);
    // free(file_msg->file_content);  // 释放内存
    free(file_msg);  // 释放内存
    return NULL;
}

int main(int argc, char **argv) {
    int port, listenfd, socketfd, hit;
    socklen_t length;
    static struct sockaddr_in cli_addr;   // 客户端地址
    static struct sockaddr_in serv_addr;  // 服务器地址

    // 注册SIGINT信号的处理函数
    signal(SIGINT, sigint_handler);
    signal(SIGTSTP,sigint_handler_for_shift);

    // 检查命令行参数是否正确
    if (argc < 3 || argc > 3 || !strcmp(argv[1], "-?")) {
        printf("Usage: %s <Port> <Directory>\n", argv[0]);
        exit(0);
    }

    if (chdir(argv[2]) == -1) {
        perror("Failed to change directory");
        exit(4);
    }

    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket creation failed");
        exit(1);
    }

    port = atoi(argv[1]);
    if (port < 1 || port > 60000) {
        fprintf(stderr, "Invalid port number: %d\n", port);
        exit(1);
    }


    // 设置服务器监听套接字
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(port);
    if (bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("bind failed");
        exit(1);
    }

    if (listen(listenfd, 64) < 0) {
        perror("listen failed");
        exit(1);
    }

    // 初始化缓存，最大缓存大小为 5
    cache = create_cache(5);


    // 初始化线程池
    read_msg_pool = thpool_init(5);
    read_file_pool = thpool_init(5);
    send_msg_pool = thpool_init(5);

    for (hit = 1;; hit++) {
        printf("yes!!!!!!!!!\r\n");

        length = sizeof(cli_addr);
        if ((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0) {
            perror("accept failed");
            continue;
        }
        printf("go!!!!!!!!!\r\n");

        webparam *param = malloc(sizeof(webparam));
        param->hit = hit; //记录请求的次数
        param->fd = socketfd;

        // 将任务加入read_msg线程池
        thpool_add_work(read_msg_pool, read_msg, param);
    }

    thpool_wait(read_msg_pool);
    thpool_wait(read_file_pool);
    thpool_wait(send_msg_pool);

    // 销毁线程池
    thpool_destroy(read_msg_pool);
    thpool_destroy(read_file_pool);
    thpool_destroy(send_msg_pool);

    // 销毁缓存
    destroy_cache(cache);

    return 0;
}
